package com.xmall.product.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.xmall.define.base.ResultCode;
import com.xmall.define.dict.IsDefaultEnum;
import com.xmall.define.dto.product.SkuImageDto;
import com.xmall.define.dto.product.SkuInfoDto;
import com.xmall.define.dto.product.SkuQuantity;
import com.xmall.define.request.product.StockLockRequest;
import com.xmall.exception.XmallException;
import com.xmall.product.define.dto.spu.SpuImageDto;
import com.xmall.product.define.request.spu.SkuInfoRequest;
import com.xmall.product.define.request.spu.SkuQueryParams;
import com.xmall.product.entity.SkuAttr;
import com.xmall.product.entity.SkuImage;
import com.xmall.product.entity.SkuInfo;
import com.xmall.product.entity.StockLockLog;
import com.xmall.product.mapper.SkuInfoMapper;
import com.xmall.product.service.*;
import com.xmall.product.service.other.IMsgService;
import com.xmall.product.service.other.IOrderTradeService;
import com.xmall.product.utils.ConvertUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.stream.Collectors;

/**
 * 商品sku信息 服务实现类
 */
@Service
public class SkuInfoServiceImpl extends ServiceImpl<SkuInfoMapper, SkuInfo> implements ISkuInfoService {

    @Resource
    private IStockLockLogService stockLockLogService;

    @Resource
    private IMsgService msgService;

    @Resource
    private IStockRevertRetryLogService stockRevertRetryLogService;

    @Resource
    private IStockDeductRetryLogService stockDeductRetryLogService;

    @Resource
    private IOrderTradeService orderTradeService;

    @Resource
    private ISpuImageService spuImageService;

    @Resource
    private ISkuAttrService skuAttrService;

    @Resource
    private ISkuImageService skuImageService;

    /**
     * 保存
     */
    @Override
    public void save(Long spuId, Map<Long, Long> attrIdMap, List<SkuInfoRequest> skuInfos) {
        skuInfos.forEach(skuInfo -> skuInfo.setSpuId(spuId));
        skuInfos.stream().forEach(skuInfoRequest -> {
            SkuInfo skuInfo = ConvertUtils.SkuModule.INSTANCE.toEntity(skuInfoRequest);
            skuInfo.setImage(skuImageService.getDefaultImage(skuInfoRequest.getSkuImageList()));
            this.save(skuInfo);

            skuAttrService.save(spuId, skuInfo.getId(), attrIdMap, skuInfoRequest.getSkuAttrList());
            skuImageService.save(spuId, skuInfo.getId(), skuInfoRequest.getSkuImageList());
        });
    }

    /**
     * 更新
     */
    @Transactional
    @Override
    public void update(Long spuId, Map<Long, Long> attrIdMap, List<SkuInfoRequest> skuInfos) {
        this.remove(new QueryWrapper<SkuInfo>().eq("spu_id", spuId));
        skuAttrService.remove(new QueryWrapper<SkuAttr>().eq("spu_id", spuId));
        skuImageService.remove(new QueryWrapper<SkuImage>().eq("spu_id", spuId));
        this.save(spuId, attrIdMap, skuInfos);
    }

    /**
     * 删除
     */
    @Transactional
    @Override
    public void delete(Long spuId) {
        this.remove(new QueryWrapper<SkuInfo>().eq("spu_id", spuId));
        skuAttrService.remove(new QueryWrapper<SkuAttr>().eq("spu_id", spuId));
        skuImageService.remove(new QueryWrapper<SkuImage>().eq("spu_id", spuId));
    }

    /**
     * sku列表
     */
    @Override
    public List<SkuInfoDto> listWithCascade(SkuQueryParams params) {
        List<SkuInfoDto> list = ConvertUtils.SkuModule.INSTANCE.doList2DtoList(this.baseMapper.listWithCascade(params));
        list.forEach(dto ->
            dto.setAttrOptionSnList(
                dto.getSkuAttrList().stream()
                .map(skuAttrDto -> skuAttrDto.getAttrOptionSn().toString())
                .collect(Collectors.toList())
            )
        );
        return list;
    }

    @Override
    public void assemblySpuAndSkuImage(Long spuId, List<SkuInfoDto> skuInfoDtoList) {
        List<SpuImageDto> spuImageDtoList = spuImageService.list(spuId);

        skuInfoDtoList.forEach(skuInfoDto -> {
            // 设置默认图片编号
            Optional<SkuImageDto> defaultSkuImage = skuInfoDto.getSkuImageList().stream().filter(skuImage -> IsDefaultEnum.YES.getValue() == skuImage.getIsDefault()).findAny();
            skuInfoDto.setDefaultSkuImageSn(defaultSkuImage.isPresent() ? defaultSkuImage.get().getSn() : null);

            // 来自spu的图片列表
            List<SkuImageDto> fromSpuImageList = skuInfoDto.getSkuImageList().stream().filter(skuImageDto -> spuImageDtoList.stream().anyMatch(spuImageDto -> skuImageDto.getSn().compareTo(spuImageDto.getSn()) == 0)).collect(Collectors.toList());
            // 来自sku的图片列表
            List<SkuImageDto> fromSkuImageList = skuInfoDto.getSkuImageList().stream().filter(skuImageDto -> spuImageDtoList.stream().noneMatch(spuImageDto -> skuImageDto.getSn().compareTo(spuImageDto.getSn()) == 0)).collect(Collectors.toList());

            // 合并图片列表
            List<SkuImageDto> skuImageList = ConvertUtils.SkuImageModule.INSTANCE.toDtoListFromSpuImage(spuImageDtoList);
            skuImageList.forEach(skuImage -> {
                skuImage.setSkuId(skuInfoDto.getId());
                skuImage.setSelected(fromSpuImageList.stream().anyMatch(spuImage -> spuImage.getSn().compareTo(skuImage.getSn()) == 0));
                skuImage.setDeletable(false);
            });
            skuImageList.addAll(fromSkuImageList);

            skuInfoDto.setSkuImageList(skuImageList);
        });
    }

    /**
     * 库存检查（返回不通过的skuId列表）
     */
    @Override
    public List<Long> stockCheck(List<SkuQuantity> skuQuantityList) {
        return skuQuantityList.stream()
            .filter(skuQuantity -> this.baseMapper.stockCheck(skuQuantity.getSkuId(), skuQuantity.getQuantity()) == 0)
            .map(SkuQuantity::getSkuId).collect(Collectors.toList());
    }

    /**
     * 库存锁定
     */
    @Transactional
    @Override
    public void stockLock(StockLockRequest request) {
        List<StockLockLog> logList = request.getSkuQuantityList().stream().map(skuQuantity -> {
            if (this.baseMapper.stockLock(skuQuantity.getSkuId(), skuQuantity.getQuantity()) == 0) {
                throw new XmallException(ResultCode.PRODUCT_STOCK_NOT_ENOUGH);
            }

            StockLockLog log = new StockLockLog();
            log.setOrderId(request.getOrderId());
            log.setSkuId(skuQuantity.getSkuId());
            log.setQuantity(skuQuantity.getQuantity());
            return log;
        }).collect(Collectors.toList());

        stockLockLogService.saveBatch(logList);
        msgService.sendStockLockMsg(request.getOrderId());
    }

    /**
     * 库存扣减
     */
    @Override
    public void stockDeduct(Long orderId) {
        if(stockDeductRetryLogService.complete(orderId)) {
            stockLockLogService.delete(orderId).forEach(stockLockLog -> this.baseMapper.stockDeduct(stockLockLog.getSkuId(), stockLockLog.getQuantity()));
        }
    }

    /**
     * 锁定的库存恢复
     */
    @Transactional
    @Override
    public void stockRevert(Long orderId) {
        if(stockRevertRetryLogService.complete(orderId) && orderTradeService.shouldExecuteStockRevert((orderId))) {
            stockLockLogService.delete(orderId).forEach(stockLockLog -> this.baseMapper.stockRevert(stockLockLog.getSkuId(), stockLockLog.getQuantity()));
        }
    }

}
